#ifndef ARM_PSCI_H
#define ARM_PSCI_H
#include "tools/macros.h"

#define PSCI_0_2_FN_BASE   0x84000000
#define PSCI_0_2_FN(n)     (PSCI_0_2_FN_BASE + (n))
#define PSCI_0_2_64BIT     0x40000000
#define PSCI_0_2_FN64_BASE (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT)
#define PSCI_0_2_FN64(n)   (PSCI_0_2_FN64_BASE + (n))

#define PSCI_0_2_FN_PSCI_VERSION        PSCI_0_2_FN(0)
#define PSCI_0_2_FN_CPU_SUSPEND         PSCI_0_2_FN(1)
#define PSCI_0_2_FN_CPU_OFF             PSCI_0_2_FN(2) 
#define PSCI_0_2_FN_CPU_ON              PSCI_0_2_FN(3)
#define PSCI_0_2_FN_MIGRATE             PSCI_0_2_FN(5)

#define PSCI_0_2_FN64_CPU_SUSPEND         PSCI_0_2_FN64(1)
#define PSCI_0_2_FN64_CPU_ON              PSCI_0_2_FN64(3)
#define PSCI_0_2_FN64_MIGRATE             PSCI_0_2_FN64(5)

#define PSCI_VERSION_MAJOR_SHIFT 16
#define PSCI_VERSION_MINOR_MASK  ((1U << PSCI_VERSION_MAJOR_SHIFT) - 1)
#define PSCI_VERSION_MAJOR_MASK  ~PSCI_VERSION_MINOR_MASK
#define PSCI_VERSION_MAJOR(ver)  (((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT)
#define PSCI_VERSION_MINOR(ver)  ((ver) & PSCI_VERSION_MINOR_MASK)

struct arm_smccc_res {
    uint64_t a0;
    uint64_t a1;
    uint64_t a2;
    uint64_t a3;
};

int32_t psci_init(void);
int32_t psci_cpu_on(uint64_t cpuid, uint64_t entry_point);
void do_smc(uint64_t function_id, uint64_t arg0, uint64_t arg1, uint64_t arg2, struct arm_smccc_res *res);

#endif
